<script setup lang="ts">
import {h} from 'vue'
import {SyncOutlined,CopyOutlined,SoundFilled,SoundOutlined,LoadingOutlined } from '@ant-design/icons-vue';
import {Bubble, theme, XProvider} from 'ant-design-x-vue';
import markdownit from 'markdown-it';
const { message } = App.useApp();

import type {BubbleMessageType} from "@/types";
import {apiAiFetch, apiVillageAgent} from "@/api/ai.ts";
import {App} from "ant-design-vue";
import useSpeech from "@/hooks/useSpeech.ts";
import zhCN from "ant-design-vue/es/locale/zh_CN";

/* 用到的工具 */
const myTheme = inject('myTheme',reactive({token:{},algorithm: theme.defaultAlgorithm}))
const currentRoute = useRoute();
const query = currentRoute.query;
const md = markdownit({ html: true, breaks: true });
const {storeUser} = useStore()

/* data */
const refTerminal=ref()
const refSender=ref()
//是否AI正在解答（推流）：当为true时，禁止切换会话、新建会话、重新提问等操作
const inPush = ref(false);
let inThink = false; //当前是否进入到思维链的推流输出中？
let conversationId = '' //本次会话id
let taskId='' //用来暂存每次发送/接收消息时对应的taskId
const hisList = ref<any>([]) //对话的聊天历史
hisList.value = [
	// {role:'user1',content:'Good morning, how are you?',taskId:'1111'},
	// {role:'assistant',content:'Hi, good morning, I\'m fine!',taskId:'2222', thinkContent:'',thinkStatus:'pending',  }
]
/*播放相关*/
const { audioSts,speechText, playSpeak, pauseSpeak, } = useSpeech({source:'village'})

/* methods */
// 发送消息事件
const handleSubmit = (sendInfo:any)=>{
	//在带有conversationId传参的路由页中，请求才正式开始
	hisList.value.push( { role:'user'+storeUser.sex, content:sendInfo.msg, taskId:taskId, },)
	hisList.value.push( { role:'assistant', content:'', taskId:taskId, loading:true }, )

	apiVillageAgent.request( {message:{content:sendInfo.msg, mode: query.mode as string, conversationId:conversationId,}}, {
		onUpdate: (data:BubbleMessageType)=>{
			//console.log(data)
			//todo: 还需要补充大模型推流文件附件过来的展示处理
			if(data.event && data.event==='workflow_started') {
				conversationId = data.conversationId || ''
				taskId = data.taskId || ''
			}else{
				if(data.mode){ hisList.value[hisList.value.length-1].loading = false } //解除loading状态，开始推流
				if(data.content.indexOf('<think>')===0){  //处理<think>标签
					inThink = true
					hisList.value[hisList.value.length-1].thinkContent = data.content.replace('<think>','')
					hisList.value[hisList.value.length-1].thinkStatus = 'pending'
				}else if(data.content.indexOf('</think>')>=0){  //处理<think>标签
					inThink = false
					const tmp = data.content.split('</think>')
					hisList.value[hisList.value.length-1].thinkContent += tmp[0]
					hisList.value[hisList.value.length-1].content += tmp[1];
					hisList.value[hisList.value.length-1].thinkStatus = 'success';
				}else{
					if(inThink){
						hisList.value[hisList.value.length-1].thinkContent += data.content
					}else{
						hisList.value[hisList.value.length-1].content += data.content
					}
				}
				nextTick(()=>{refTerminal.value.scrollToBottom()})
			}
		},
		onSuccess: (data:BubbleMessageType)=>{
			inPush.value = false;
			hisList.value[hisList.value.length-1].content += data.content
			nextTick(()=>{refTerminal.value.scrollToBottom()})
		},
		onError: (error:any)=>{
			if(hisList.value[hisList.value.length-1].thinkStatus && inThink) {
				inThink = false
				hisList.value[hisList.value.length-1].thinkStatus = 'error';
			}
			console.log(error)
		},
	} );
}

const handleStop=()=>{
	apiAiFetch.stopMessage('village', taskId, ()=>{
		if(hisList.value[hisList.value.length-1].thinkStatus){
			hisList.value[hisList.value.length-1].thinkStatus = 'error';
		}
	})
}

//对某个提示的答案觉得不满意后，让AI重新回答
const reAsk = (index:number)=>{
	refSender.value.setTextContent( hisList.value[index-1].content );
	nextTick(()=>{
		refSender.value.handleMsgSubmit(refSender.value.value)
	})
}
//在开场白推荐的提问语列表中选一个，让AI进行回答
const askWithText = (text:string)=>{
	refSender.value.setTextContent( text );
	nextTick(()=>{
		refSender.value.handleMsgSubmit(refSender.value.value)
	})
}
//复制消息内容
const copyContent = (text:string)=>{
	navigator.clipboard.writeText(text)
		.then(() => {
			message.success('文本已复制到剪贴板');
		})
		.catch(err => {
			message.error('复制失败:'+(err.message||''));
		});
}

//清除历史记录事件
const handleClearHistory=()=>{
	apiAiFetch.deleteConversation('village', conversationId as string, ()=>{ //先删除本会话
		conversationId = '' //再进行清屏
		hisList.value=[]
	})
}

//todo: 以下程序执行暂时保留；如果可以通过python在dify那边实现，则这里就注释掉
//beforeMounted : 每次打开都要删除前一次的对话
apiAiFetch.loadConversations('village', (body:any)=>{
	for(let item of (body.data as any[])){
		apiAiFetch.deleteConversation('village',item.id)
	}
})

</script>

<template>
	<XProvider :theme="myTheme" :locale="zhCN">
	<div class="container">
		<terminal :hidden="(!conversationId || conversationId==='') && hisList.length===0" :clear-history="hisList.length>0" ref="refTerminal" @onClearHistory="handleClearHistory">
			<template v-for="(item,index) in hisList" :key="index">
				<Bubble v-if="item.role==='user1'||item.role==='user0'" placement="end" :content="item.content" shape="corner"/>
				<Bubble v-else-if="item.role==='assistant'" placement="start" :content="item.content"  variant="outlined" shape="corner"
						:loading="item.loading">
					<template #message>
						<think-process v-if="item.thinkStatus" :status="item.thinkStatus"><div class="md" v-html="md.render(item.thinkContent)"/></think-process>
						<div class="md" v-html="md.render(item.content)"/>
					</template>
					<template #footer>
						<a-space v-if="!inPush" size="small">
							<a-button type="text" size="small" :icon="h(SyncOutlined)" @click="reAsk(index)" />
							<a-button v-if="item.content && item.content.length>0" type="text" size="small" :icon="h(CopyOutlined)" @click="copyContent(item.content)" />
							<a-button v-if="audioSts===-1 || audioSts===1 || (audioSts===2&&speechText!==item.content)" title="语音播放" type="text" size="small" :icon="h(SoundOutlined)" @click="playSpeak(item.content)" />
							<LoadingOutlined v-else-if="audioSts===0 && speechText===item.content" style="color:var(--info-color)"/>
							<a-button v-else-if="audioSts===2 && speechText===item.content" title="暂停语音" style="color:var(--primary-color)" type="text" size="small" :icon="h(SoundFilled)" @click="pauseSpeak()" />
						</a-space>
					</template>
				</Bubble>
			</template>
		</terminal>
		<welcome-screen v-if="(!conversationId || conversationId==='') && hisList.length===0" :moreTools="false" @textSelected="askWithText" welcome-source="village"/>
		<sender-simple @onSend="handleSubmit" @onCancel="handleStop" ref="refSender" source="village"/>
	</div>
	</XProvider>
</template>

<style scoped lang="scss">
.container{height:100vh}
:deep(.sender-wrapper){margin-top:auto;}
:deep(.ant-bubble-content p:last-child){margin-bottom:0}
:deep(.ant-bubble .ant-bubble-footer) {
	margin-top:2px;
	.ant-btn{color:var(--font-secondary-color)}
	//.ant-btn.ant-btn-sm{font-size:16px;}
}
:deep(.ant-bubble-content .ant-attachment-list-card-status-done:not(.ant-attachment-list-card-status-error)){cursor:pointer;}
</style>